<?php
class App{
    public $language = 'zh-TW';
	public static $classMap = [];
    public static $app;
    public static $aliases = ['@app' => __DIR__.'/app'];
    private $_components = [];
    private static $_singletons = [];
	private $_params = [];
    public $f3;
    public function __construct($f3, $config){
        $this->f3 = $f3;
        self::$app = $this;
        $this->_components = $this->codeComponents();
        if(!empty($config['components'])){
            $this->_components = array_merge($this->_components, $config['components']);
            unset($config['components']);
        }
        if(!empty($config['f3'])){
            foreach ($config['f3'] as $key => $value) {
                call_user_func_array([$this->f3, $key], $value);
            }
        }
        $this->_params = $config;
    }
    private function codeComponents(){
        return [
            'fileManger' => 'app\bin\Local',
            'path' => 'app\utils\Path',
            'request' => 'app\utils\Request',
            'csrf' => 'app\utils\Csrf',
            'session' => 'app\utils\Session',
        ];
    }

    public function addRoute($route, $callback){
        call_user_func_array([$this->f3, 'route'], [$route, $callback]);
    }
	public static function getAlias($alias)
    {
        if (strncmp((string)$alias, '@', 1) !== 0) {
            // not an alias
            return $alias;
        }

        $pos = strpos($alias, '/');
        $root = $pos === false ? $alias : substr($alias, 0, $pos);

        if (isset(static::$aliases[$root])) {
            if (is_string(static::$aliases[$root])) {
                return $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos);
            }

            foreach (static::$aliases[$root] as $name => $path) {
                if (strpos($alias . '/', $name . '/') === 0) {
                    return $path . substr($alias, strlen($name));
                }
            }
        }

        return false;
    }
    public static function setAlias($alias, $path)
    {
        if (strncmp($alias, '@', 1)) {
            $alias = '@' . $alias;
        }
        $pos = strpos($alias, '/');
        $root = $pos === false ? $alias : substr($alias, 0, $pos);
        if ($path !== null) {
            $path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
            if (!isset(static::$aliases[$root])) {
                if ($pos === false) {
                    static::$aliases[$root] = $path;
                } else {
                    static::$aliases[$root] = [$alias => $path];
                }
            } elseif (is_string(static::$aliases[$root])) {
                if ($pos === false) {
                    static::$aliases[$root] = $path;
                } else {
                    static::$aliases[$root] = [
                        $alias => $path,
                        $root => static::$aliases[$root],
                    ];
                }
            } else {
                static::$aliases[$root][$alias] = $path;
                krsort(static::$aliases[$root]);
            }
        } elseif (isset(static::$aliases[$root])) {
            if (is_array(static::$aliases[$root])) {
                unset(static::$aliases[$root][$alias]);
            } elseif ($pos === false) {
                unset(static::$aliases[$root]);
            }
        }
    }
    
    public static function configure($object, $properties)
    {
        foreach ($properties as $name => $value) {
            $object->$name = $value;
        }

        return $object;
    }

    public static function t($category, $message, $params = [], $language = null){

    }

	public static function autoload($className)
    {
        if (isset(static::$classMap[$className])) {
            $classFile = static::$classMap[$className];
            if (strncmp($classFile, '@', 1) === 0) {
                $classFile = static::getAlias($classFile);
            }
        } elseif (strpos($className, '\\') !== false) {
            $classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false);
            if ($classFile === false || !is_file($classFile)) {
                return;
            }
        } else {
            return;
        }

        include $classFile;
    }

    public function __get($name){
        if(isset($this->_components[$name])){
            $objectConfig = is_string($this->_components[$name]) ? ['class'=>$this->_components[$name]] : $this->_components[$name];
            $objectConfig['id'] = is_string($name) ? $name : $objectConfig['class'];
            return self::createObject($objectConfig);
        }else if(isset($this->$name)){
            return $this->$name;
        }
        return FALSE;
    }
    public static function createObject($type, array $params = []){
        if(is_string($type)){
            $className = $type;
            if(isset(self::$_singletons[$className])) return self::$_singletons[$className];
            $class = new $type($params);
            self::$_singletons[$className] = self::configure($class, $params);
            return self::$_singletons[$className];
        }else if(is_array($type)){
            if(isset($type['class'])){
                $className = $type['class'];
                $id = isset($type['id']) ? $type['id'] : $className;
                if(isset(self::$_singletons[$id])) return self::$_singletons[$id];
                $class = new $className($params);
                unset($type['class']);
                unset($type['id']);
                self::$_singletons[$id] = self::configure($class, $type);
                return self::$_singletons[$id];
            }
        }
        throw new \Exception("Error Create object ".json_encode($type), 5000);
    }
    public function getOption($key){
        return isset($this->_params[$key]) ? $this->_params[$key] : '';
    }
    public function run(){
        $this->f3->run();
    }
}

spl_autoload_register(['App', 'autoload'], true, true);